// Usage1: ./testdominion <#number of tests>
// Usage2: make systemtest; file testdominion.out is created.

#include "includes.h"

#include <assert.h>
#include <stdbool.h>

FILE *file;


int inSupply(struct gameState *game, int card)
{
    int cardCount = game->supplyCount[card];
    if (cardCount > 0)
    {
        return 1;
    }
    return 0;
}

void buyPhase(struct gameState *game, int money)
{
    int flip;
    int check;
    int player = whoseTurn(game);
    if (money >= 8)
    {
        if (inSupply(game, province))
        {
            //victory cards: province
            fprintf(file, "%d: bought Province\n", player);
            check = buyCard(province, game);
            assert(check == 0);
        }
    }
    else if (money >= 6)
    {
        //action cards: adventurer
        //treasure cards: gold
        flip = floor(Random() * 2); // randomly chose: buy gold or adventurer
        fprintf(file, "flip: %d\n", flip);
        if (flip == 0)
        {
            if (inSupply(game, gold))
            {
                fprintf(file, "%d: bought Gold\n", player);
                check = buyCard(gold, game);
                assert(check == 0);
            }
        }
        else if (flip == 1)
        {
            if (inSupply(game, adventurer))
            {
                fprintf(file, "%d: bought Adventurer\n", player);
                check = buyCard(adventurer, game);
                assert(check == 0);
            }
        }
    }
    else if (money >= 5)
    {
        //action cards(5): council room(id:8), mine(id:11), minion(id:17,choice1&2), tribute(id:19), outpost(id:23)
        //victory cards(5): duchy
        flip = floor(Random() * 2); // randomly chose: buy victory card or action card
        if (flip == 0)
        {
            if (inSupply(game, duchy))
            {
                fprintf(file, "%d: bought Duchy\n", player);
                check = buyCard(duchy, game);
                assert(check == 0);
            }
        }
        else if (flip == 1)
        {
            int actFive[5] = {council_room, mine, minion, tribute, outpost};
            int cardIdx = floor(Random() * 5);
            //randomly choose a card and check if it is purchasable(part of kcard set and in supply)
            if (inSupply(game, actFive[cardIdx]))
            {
                char name[MAX_STRING_LENGTH];
                cardNumToName(actFive[cardIdx], name);
                fprintf(file, "%d: bought %s\n", player, name);
                check = buyCard(actFive[cardIdx], game);
                assert(check == 0);
            }
        }
    }
    else if (money >= 4)
    {
        //action cards(4): feast, garden(not really an action), remodel, smithy, baron, cutpurse, salvager, sea hag, treasure map
        int actFour[9] = {feast, gardens, remodel, smithy, baron, cutpurse, salvager, sea_hag, treasure_map};
        int cardIdx = floor(Random() * 9);
        //randomly choose a card and check if it is purchasable(part of kcard set and in supply)
        if (inSupply(game, actFour[cardIdx]))
        {
            char name[MAX_STRING_LENGTH];
            cardNumToName(actFour[cardIdx], name);
            fprintf(file, "%d: bought %s\n", player, name);
            check = buyCard(actFour[cardIdx], game);
            assert(check == 0);
        }
    }
    else if (money >= 3)
    {
        //treasure cards(3): silver
        //action cards(3): village, great hall, steward, ambassador
        flip = floor(Random() * 2); // randomly chose: buy treasure card or action card
        if (flip == 0)
        {
            if (inSupply(game, silver))
            {
                fprintf(file, "%d: bought Silver\n", player);
                check = buyCard(silver, game);
                assert(check == 0);
            }
        }
        else if (flip == 1)
        {
            int actThree[4] = {village, great_hall, steward, ambassador};
            int cardIdx = floor(Random() * 4);
            //randomly choose a card and check if it is purchasable(part of kcard set and in supply)
            if (inSupply(game, actThree[cardIdx]))
            {
                char name[MAX_STRING_LENGTH];
                cardNumToName(actThree[cardIdx], name);
                fprintf(file, "%d: bought %s\n", player, name);
                check = buyCard(actThree[cardIdx], game);
                assert(check == 0);
            }
        }
    }
    else if (money >= 2)
    {
        //action cards(2): embargo
        //victory cards(2): estate
        flip = floor(Random() * 2); // randomly chose: buy action card or victory card
        if (flip == 0)
        {
            if (inSupply(game, estate))
            {
                fprintf(file, "%d: bought Estate\n", player);
                check = buyCard(estate, game);
                assert(check == 0);
            }
        }
        else if (flip == 1)
        {
            if (inSupply(game, embargo))
            {
                fprintf(file, "%d: bought Embargo\n", player);
                check = buyCard(embargo, game);
                assert(check == 0);
            }
        }
    }
    //treasure cards(0): copper
}

void actionPhase(struct gameState *game, int k[10])
{
    //Play first action card in hand
    int choice1 = -1; int choice2 = -1; int choice3 = -1; int flip; int check;
    int player = whoseTurn(game);
    int handCount = game->handCount[player];
    int handIndex;
    for (handIndex = 0; handIndex < handCount; handIndex++)
    {
        int card = game->hand[player][handIndex];
        if (card >= adventurer)
        {
            if (card == feast)
            {
                bool ok = false;
                while (ok == false)
                {
                    choice1 = floor(Random() * NUM_K_CARDS);
                    if (getCardCost(k[choice1]) <= 5)
                    {
                        ok = true;
                    }
                }
                if (inSupply(game, k[choice1]))
                {
                    char name[MAX_STRING_LENGTH];
                    char name2[MAX_STRING_LENGTH];
                    cardNumToName(card, name);
                    cardNumToName(k[choice1], name2);
                    fprintf(file, "Player %d plays %s, gains %s\n\n", player, name, name2);
                    check = playCard(handIndex, k[choice1], choice2, choice3, game);
                    assert(check == 0);
                }
                break;
            }
            else if (card == baron)
            {
                char name[MAX_STRING_LENGTH];
                cardNumToName(card, name);
                fprintf(file, "Player %d plays %s, chose %d\n\n", player, name, choice1);
                choice1 = floor(Random() * 2);
                check = playCard(handIndex, choice1, choice2, choice3, game);
                assert(check == 0);
                break;
            }
            else if (card == minion)
            {
                flip = floor(Random() * 2);
                if (flip == 1)
                {
                    char name[MAX_STRING_LENGTH];
                    cardNumToName(card, name);
                    fprintf(file, "Player %d plays %s, chose choice %d\n\n", player, name, 1);
                    choice1 = 1;
                    check = playCard(handIndex, choice1, choice2, choice3, game);
                    assert(check == 0);
                }
                else if (flip == 0)
                {
                    char name[MAX_STRING_LENGTH];
                    cardNumToName(card, name);
                    fprintf(file, "Player %d plays %s, chose choice %d\n\n", player, name, 2);
                    choice2 = 1;
                    check = playCard(handIndex, choice1, choice2, choice3, game);
                    assert(check == 0);
                }
                break;
            }
            else if (card == steward)
            {
                flip = floor(Random() * 3);
                if (flip == 1)
                {
                    char name[MAX_STRING_LENGTH];
                    cardNumToName(card, name);
                    fprintf(file, "Player %d plays %s, chose choice %d\n\n", player, name, choice1);
                    choice1 = 3;
                    check = playCard(handIndex, choice1, choice2, choice3, game);
                    assert(check == 0);
                }
                else if (flip == 0)
                {
                    char name[MAX_STRING_LENGTH];
                    cardNumToName(card, name);
                    fprintf(file, "Player %d plays %s, chose choice %d\n\n", player, name, choice1);
                    choice1 = 2;
                    check = playCard(handIndex, choice1, choice2, choice3, game);
                    assert(check == 0);
                }
                else
                {
                    char name[MAX_STRING_LENGTH];
                    cardNumToName(card, name);
                    fprintf(file, "Player %d plays %s, chose choice %d\n\n", player, name, choice1);
                    choice1 = 1;
                    check = playCard(handIndex, choice1, choice2, choice3, game);
                    assert(check == 0);
                }
                break;
            }
            else if (card == ambassador)
            {
                /*
                choice2 = floor(Random()*2)+1;
                bool ok = false;
                while (ok == false) {
                    choice1 = floor(Random()*handCount);
                    if (choice1 != handIndex){
                        ok = true;
                    }
                }
                char name[MAX_STRING_LENGTH];
                char name2[MAX_STRING_LENGTH];
                cardNumToName(card, name);
                cardNumToName(handCard(choice1, game), name2);
                fprintf(file,"Player %d plays %s, choice2(return to supply): %d, choice1(card hand index): %d, card name: %s\n\n", player, name, choice2, choice1, name2);
                check = playCard(handIndex, choice1, choice2, choice3, game);
                assert(check == 0); //TODO: need to check if there is more than one copy
                */
                break;
            }
            else if (card == embargo)
            {
                bool ok = false;
                while (ok == false)
                {
                    choice1 = floor(Random() * NUM_TOTAL_K_CARDS);
                    if (game->supplyCount[choice1] > 0)
                    {
                        ok = true;
                    }
                }
                char name[MAX_STRING_LENGTH];
                char name2[MAX_STRING_LENGTH];
                cardNumToName(card, name);
                cardNumToName(choice1, name2);
                fprintf(file, "Player %d plays %s, choice1: %s\n\n", player, name, name2);
                check = playCard(handIndex, choice1, choice2, choice3, game);
                assert(check == 0);
                break;
            }
            else if (card == salvager)
            {
                bool ok = false;
                while (ok == false)
                {
                    choice1 = floor(Random() * handCount);
                    if (choice1 != handIndex)
                    {
                        ok = true;
                    }
                }
                char name[MAX_STRING_LENGTH];
                char name2[MAX_STRING_LENGTH];
                cardNumToName(card, name);
                cardNumToName(handCard(choice1, game), name2);
                check = playCard(handIndex, choice1, choice2, choice3, game);
                fprintf(file, "Player %d plays %s, trashed: %s\n\n", player, name, name2);
                assert(check == 0);
                break;
            }
            else if (card == mine)
            {
                int x = 0; int e; //int cost1,cost2;
                while (x < handCount)
                {
                    choice1 = x;
                    e = handCard(choice1, game);
                    if (choice1 != handIndex && (e == copper || e == silver || e == gold))
                    {
                        x = handCount + 10;
                    }
                    x++;
                }
                if (x != (handCount + 10 + 1))
                {
                    break;
                }
                if (e == gold)
                {
                    choice2 = gold;
                }
                else if (e == silver)
                {
                    choice2 = gold;
                }
                else
                {
                    choice2 = silver;
                }
                char name[MAX_STRING_LENGTH];
                char name2[MAX_STRING_LENGTH];
                char name3[MAX_STRING_LENGTH];
                cardNumToName(card, name);
                cardNumToName(handCard(choice1, game), name2);
                cardNumToName(choice2, name3);
                fprintf(file, "Player %d plays %s, trashes: %s gains: %s\n\n", player, name, name2, name3);
                check = playCard(handIndex, choice1, choice2, choice3, game);
                assert(check == 0);
                break;
            }
            else if (card == remodel)
            {
                bool ok = false; int cost1, cost2, e;
                while (ok == false)
                {
                    choice1 = floor(Random() * handCount);
                    if (choice1 != handIndex)
                    {
                        ok = true;
                    }
                }
                ok = false;
                e = handCard(choice1, game);
                cost1 = getCost(e);
                while (ok == false)
                {
                    while (choice2 < adventurer)
                    {
                        choice2 = floor(Random() * NUM_TOTAL_K_CARDS);
                    }
                    cost2 = getCost(choice2);
                    if (game->supplyCount[choice2] > 0 && (cost2 <= (cost1 + 2)) && (choice2 > 0))
                    {
                        ok = true;
                    }
                }
                char name[MAX_STRING_LENGTH];
                char name2[MAX_STRING_LENGTH];
                char name3[MAX_STRING_LENGTH];
                cardNumToName(card, name);
                cardNumToName(handCard(choice1, game), name2);
                cardNumToName(choice2, name3);
                if (inSupply(game, choice2))
                {
                    fprintf(file, "Player %d plays %s, trashed: %s, gains: %s\n\n", player, name, name2, name3);
                    check = playCard(handIndex, choice1, choice2, choice3, game);
                    assert(check == 0);
                }
                break;
            }
            else
            {
                if (card != treasure_map && card != gardens)   //TODO
                {
                    char name[MAX_STRING_LENGTH];
                    cardNumToName(card, name);
                    fprintf(file, "Player %d plays %s\n\n", player, name);
                    check = playCard(handIndex, choice1, choice2, choice3, game);
                    assert(check == 0);
                }
                break;
            }
        }
    }
}

int main (int argc, char **argv)
{

    //random test seed
    time_t testSeed;
    srand((unsigned) time(&testSeed));
    //srand(1393191888); //to test or regenerate a game with a specific seed, enter seed, unblock this and comment out above
    file = fopen ("gameResults.out", "w");
    int t;
    for (t = 0; t < atoi(argv[1]); t++)
    {

        int gameSeed, numPlayer, i;
        int k[10] = {0};
        struct gameState g;
        struct gameState *game = &g;

        //random game seed
        gameSeed = rand() % 1000 + 1;
        //gameSeed = 804;
        //random number of players 2-4
        numPlayer = (rand() % 3) + 2;
        //numPlayer = 4;
        //random set of kingdom cards
        selectKingdomCards(gameSeed, k);
        //initialize game
        memset(game, 0, sizeof(struct gameState));
        initializeGame(numPlayer, k, gameSeed, game);

        fprintf(file, "Test Seed: %d\n", (int)testSeed);
        fprintf(file, "Game Seed: %d\n", gameSeed);
        fprintf(file, "Number of Players: %d\n", numPlayer);
        fprintf(file, "Kingdom Cards:\n");
        for (i = 0; i < 10; i++)
        {
            char name[MAX_STRING_LENGTH];
            cardNumToName(k[i], name);
            fprintf(file, "  %-2d %-13s %-2d\n", k[i], name, getCardCost(k[i]));
        }
        fprintf(file, "\n");

        i = 0;
        int money = 0;
        int turn = 0;
        //Start Game
        while (!isGameOver(game))
        {
            money = 0;
            fprintf(file, "Turn: #%d\n", turn);
            money = countHandCoins(whoseTurn(game), game);
            fprintf(file, "Money: %d\n", money);

            //action phase
            actionPhase(game, k);
            //buy phase
            money = countHandCoins(whoseTurn(game), game);
            buyPhase(game, money);
            fprintf(file, "%d: end turn\n\n", whoseTurn(game));
            endTurn(game);

            turn++;
        } // end of While

        fprintf(file, "Finished game.\n");

        if (numPlayer == 2)
        {
            fprintf(file, "Player 0: %d\nPlayer 1: %d\n", scoreFor(0, game), scoreFor(1, game));
        }
        else if (numPlayer == 3)
        {
            fprintf(file, "Player 0: %d\nPlayer 1: %d\nPlayer 2: %d\n", scoreFor(0, game), scoreFor(1, game), scoreFor(2, game));
        }
        else
        {
            fprintf(file, "Player 0: %d\nPlayer 1: %d\nPlayer 2: %d\nPlayer 3: %d\n", scoreFor(0, game), scoreFor(1, game), scoreFor(2, game), scoreFor(3, game));
        }

    }
    return 0;

}
